import 'package:gate_cli/models/json_clz.dart';
import 'package:gate_cli/models/res_config.dart';
import 'package:code_builder/code_builder.dart';

class JsonCommandUtil {
  JsonCommandUtil._();

  /// 获取字段类型
  static String getType(v) {
    if (v is String) {
      return 'String';
    } else if (v is int) {
      return 'int';
    } else if (v is double) {
      return 'double';
    } else if (v is bool) {
      return 'bool';
    } else if (v == null) {
      return 'dynamic';
    } else if (v is List) {
      return 'List';
    } else {
      return 'Class';
    }
  }

  /// 子类型匹配，列表以及列表中类型的匹配
  static String _subType(JsonType? jsonType, ResJson resJson) {
    if (jsonType == null) return "";
    final parentName = jsonType.name;
    if (parentName == null || parentName.isEmpty) return "";
    final value = resJson.camelCase ? jsonType.formatValue : jsonType.value;
    if (jsonType.subType == null && jsonType.subClz == null) {
      return jsonType.name ?? "";
    }
    if (jsonType.subType != null) {
      return "${jsonType.name}<${_subType(jsonType.subType, resJson)}>? $value;";
    }
    if (jsonType.subClz != null) {
      return _subClz(jsonType.subClz);
    }
    return "";
  }

  static String _subClz(JsonClz? jsonClz) {
    if (jsonClz == null) return "";
    final clzName = jsonClz.clzName;
    return clzName;
  }

  static String? buildClz(JsonClz? clz, ResJson resJson) {
    if (clz == null) return '';
    String result = '';
    final emitter = DartEmitter();
    final jClz = Class((classBuild) => classBuild
      ..name = clz.clzName
      ..fields.addAll(clz.attributes.map((e) => JsonCommandUtil.buildField(e, clz.resJson)).whereType())
      ..annotations.add(refer('JsonSerializable()'))
      ..constructors.add(Constructor((c) => c
        ..optionalParameters
            .addAll(clz.attributes.map((e) => JsonCommandUtil.buildParameter(e, clz.resJson)).whereType())))
      ..constructors.add(Constructor((c) => c
        ..redirect
        ..name = 'fromJson'
        ..factory = true
        ..docs.add('/// Json 转 ${clz.clzName}')
        ..requiredParameters.add(Parameter((p) => p
          ..name = 'json'
          ..type = refer('Map<String, dynamic>')))
        ..body = refer('_\$${clz.clzName}FromJson(json)').code))
      ..methods.add(Method((m) => m
        ..name = 'toJson'
        ..docs.add('/// ${clz.clzName} 转 Json')
        ..returns = refer('Map<String, dynamic>')
        ..body = refer('_\$${clz.clzName}ToJson(this)').code)));
    result += '${jClz.accept(emitter)}';
    result += clz.attributes
        .map((e) => _buildSubClz(e, resJson))
        .whereType()
        .where((element) => element.isNotEmpty)
        .join('\n');
    return result;
  }

  static String? _buildSubClz(JsonType? jsonType, ResJson resJson) {
    if (jsonType == null) return "";
    final sbClz = jsonType.subClz;
    final subType = jsonType.subType;
    return "${buildClz(sbClz, resJson)}\n${_buildSubClz(subType, resJson)}";
  }

  static Field? buildField(JsonType jsonType, ResJson resJson) {
    final typeName = jsonType.name;
    if (typeName == null || typeName.isEmpty) return null;
    final value = resJson.camelCase ? jsonType.formatValue : jsonType.value;
    final jValue = jsonType.value;
    return Field((fieldBuild) {
      if (jValue != null && jValue.isNotEmpty && resJson.jsonKey) {
        Map<String, Expression> namedArguments = {
          'name': literalString(jValue),
        };
        if (resJson.safelyConvert) {
          if (jsonType.name == 'int') {
            namedArguments['fromJson'] = CodeExpression(Code('GTConverter.intValue'));
          } else if (jsonType.name == 'double') {
            namedArguments['fromJson'] = CodeExpression(Code('GTConverter.doubleValue'));
          } else if (jsonType.name == 'String') {
            namedArguments['fromJson'] = CodeExpression(Code('GTConverter.stringValue'));
          } else if (jsonType.name == 'bool') {
            namedArguments['fromJson'] = CodeExpression(Code('GTConverter.boolValue'));
          }
        }
        fieldBuild.annotations.add(
          refer('JsonKey').call([], namedArguments),
        );
      }
      fieldBuild
        ..name = value
        ..type = refer(_typeRefer(jsonType, resJson));
    });
  }

  static Parameter? buildParameter(JsonType jsonType, ResJson resJson) {
    final typeName = jsonType.name;
    if (typeName == null || typeName.isEmpty) return null;
    final value = resJson.camelCase ? jsonType.formatValue : jsonType.value;
    if (value == null || value.isEmpty) return null;
    return Parameter((p) => p
      ..name = value
      ..named = true
      ..toThis = true);
  }

  static String _typeRefer(JsonType jsonType, ResJson resJson) {
    final typeName = jsonType.name;
    if (typeName == null || typeName.isEmpty) return 'dynamic';
    if (jsonType.subType == null && jsonType.subClz == null) {
      return '$typeName?';
    }
    if (jsonType.subType != null) {
      return '${jsonType.name}<${_subType(jsonType.subType, resJson)}>?';
    }
    if (jsonType.subClz != null) {
      return '${_subClz(jsonType.subClz)}?';
    }
    return 'dynamic';
  }

  static String buildHeader(JsonClz clz, ResJson resJson) {
    if (!resJson.jsonKey) return "";
    String header = '';
    if (resJson.safelyConvert) {
      header += 'import \'package:biz_base/utils/gt_converter.dart\';\n';
    }
    header += '''
    import 'package:json_annotation/json_annotation.dart';
    
    part '${clz.fileName}.g.dart';
    
    ''';
    return header;
  }
}
